package nsga;

import java.util.LinkedList;
import java.util.List;

import common.BasicAgent;
import common.GeneticHelper;
import common.GeneticOperations;

public class Individual <Genotype> implements BasicAgent<Genotype> {
    
	public Genotype genotype;
	public GeneticOperations<Genotype> go;

	public List<Individual<Genotype>> dominateSet = new LinkedList<Individual<Genotype>>();
	public int dominatedByNbr = 0;
	public double distance = 0.0;
	
	private List<Double> values = null;	
	private List<Double> fitnesses = null;	
	public Integer rank = null;
	
	public Individual(Genotype genotype, GeneticOperations<Genotype> go)
	{
		this.genotype = genotype;
		this.go = go;

		calculateValues();
	}
	

	List<Individual<Genotype>> crossover(Individual<Genotype> ind2)
	{
	    List<Individual<Genotype>> result = new LinkedList<Individual<Genotype>>();
	    List<Genotype> childrenGenotypes = go.crossover(this.getGenotype(), ind2.getGenotype());
	    for (Genotype genotype : childrenGenotypes) {
	        result.add(new Individual<Genotype>(genotype,this.go));
	    }
	    return result;
	}
	
	/**
	 * Zwraca zmutowanego osobnika
	 * @return
	 */
	public Individual<Genotype> mutated() 
	{    
	    Genotype mutatedGenotype = go.duplicateGenotype(genotype);
	    go.mutate(mutatedGenotype);
	    
	    Individual<Genotype> mutatedInd = new Individual<Genotype>(mutatedGenotype,go);
	    mutatedInd.calculateValues();

	    return mutatedInd;
	}
	
	@Override
    public int checkDomination(BasicAgent<Genotype> agent) {
	    
	    return GeneticHelper.checkDomination(this, agent);
    }

	public void calculateValues() {
	    this.values = go.getValues(genotype);
	    this.fitnesses = go.getFitnessesFromValue(this.values);
	}
	
    public List<Double> getValues() {
        return this.values;
    }
    
    public double getValue(int i) {
        return this.values.get(i);
    }
    

    public String toString() {
            StringBuffer sb = new StringBuffer();
            for(int i = 0; i < this.getValues().size(); i++) {
                sb.append(String.format("%.16f",this.getValue(i)).replace(",", "."));
                if (i != this.getValues().size() - 1) {
                    sb.append(" ");
                }
            }
            return sb.toString(); 
    }
    
    public Genotype getGenotype() {
        return genotype;
    }


    @Override
    public double getFitness(int index) {
        return this.fitnesses.get(index);
    }


    @Override
    public List<Double> getFitnesses() {
        return this.fitnesses;
    }
}
